package dk.controlme.lego.server;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Created with inspiration from
 * http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html
 *
 * By Jakob Rosenlund
 */
public class LegoServer implements HttpConstants {

    // Debug?
    static boolean _DEBUG = false;
    // Log-file lock
    static PrintStream log = null;
    // Configuration file
    protected static Properties properties = new Properties();
    // Idle workers
    static Vector threads = new Vector();
    // Virtual root
    static File root;
    // Client timeout
    static int timeout = 0;
    // Max number worker threads
    static int workers = 5;

    /* Debug method */
    protected static void debug(String str) {
        if(_DEBUG) System.out.println(str);
    }

    /* Logging method */
    protected static void log(String str) {
        synchronized(log) {
            debug(str);
            log.println(str);
            log.flush();
        }
    }

    /* Load legoserver.conf from run-directory */
    static void loadProperties() throws IOException {
        File configFile = new File(System.getProperty("java.home") + File.separator + "legoserver.conf");
        // Read in settings from config file
        if(configFile.exists()) {
            InputStream inputStream = new BufferedInputStream(new FileInputStream(configFile));
            properties.load(inputStream);
            inputStream.close();
            String propertyValue;

            // Read in debug boolean
            propertyValue = properties.getProperty("debug");
            if(propertyValue != null) {
                _DEBUG = Boolean.getBoolean(propertyValue);
            }

            // Read in logfile location
            propertyValue = properties.getProperty("logfile");
            if(propertyValue != null) {
                debug("Opening logfile: "+propertyValue);
                log = new PrintStream(
                        new BufferedOutputStream(
                          new FileOutputStream(propertyValue)
                        )
                      );
            }

            // Read in root directory
            propertyValue = properties.getProperty("root");
            if(propertyValue != null) {
                root = new File(propertyValue);
                if (!root.exists()) {
                    log(root + " isn't a valid server root.");
                    System.exit(-1);
                } else {
                    log("Root successfully set to "+root);
                }
            }

            // Read in client timeout
            propertyValue = properties.getProperty("client_timeout");
            if(propertyValue != null) {
                timeout = Integer.parseInt(propertyValue);
                log("Client timeout set to " + timeout);
            }

            // Read in number of workers
            propertyValue = properties.getProperty("num_workers");
            if(propertyValue != null) {
                workers = Integer.parseInt(propertyValue);
                log("Number of worker threads set to "+workers);
            }

        }
        // Make sure everything is loaded, else load defaults
        if(root==null) root = new File(System.getProperty("user.dir"));
        if(timeout<=1000) timeout = 5000;
        if(workers>25) workers = 5;
        if(log==null) {
            debug("Logging to stdout.");
            log = System.out;
        }

    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        if(args.length > 0) {
            port = Integer.parseInt(args[0]);
        }
        loadProperties();
        /* Start workers */
        for(int i = 0 ; i < workers ; ++i) {
            Worker worker = new Worker();
            (new Thread(worker, "worker #"+i)).start();
            threads.addElement(worker);
        }

        ServerSocket serverSocket = new ServerSocket(port);
        while(true) {
            Socket socket = serverSocket.accept();
            Worker worker = null;
            synchronized(threads) {
                // If empty, create a worker and use it
                if(threads.isEmpty()) {
                    Worker workerSocket = new Worker();
                    workerSocket.setSocket(socket);
                    (new Thread(workerSocket, "Additional worker")).start();
                // Else use the first available and remove afterwards.
                } else {
                    worker = (Worker) threads.elementAt(0);
                    threads.removeElementAt(0);
                    worker.setSocket(socket);
                }
            }
        }
    }
}
